Add a runtime create_model variant to the schema_validators example#3148
Open
Aaron-Oh wants to merge 2 commits into
Open
Add a runtime create_model variant to the schema_validators example#3148Aaron-Oh wants to merge 2 commits into
Aaron-Oh wants to merge 2 commits into
Conversation
The story showed four ways to type a tool parameter (BaseModel, TypedDict, dataclass, dict). Add a fifth: a pydantic model built at runtime with create_model from an external JSON Schema dict, then handed to @mcp.tool() like any BaseModel. Covers the doc gap behind issues modelcontextprotocol#323, modelcontextprotocol#761, modelcontextprotocol#772. A create_model() result is opaque to static type checkers, so a TYPE_CHECKING branch aliases it to a same-shape declared model while the runtime uses the dynamic class. server_lowlevel.py, client.py and README.md are updated to include the new variant.
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- server.py: JSON Schema 'required' is optional, so default it to an empty list before membership testing. External schemas with only optional properties no longer raise KeyError at import time. - README.md: greet_dynamic publishes the same schema as greet_pydantic, so the client bullet now says four typed variants, not three.
Author
|
Thanks for the review — addressed both in 230f718:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The
schema_validatorsexample story shows four ways to type a toolparameter so
MCPServerderives and enforcesinputSchema: a pydanticBaseModel, aTypedDict, a@dataclass, and a baredict[str, Any].This adds a fifth variant: a pydantic model built at runtime with
create_modelfrom an external JSON Schema dict, then handed to@mcp.tool()exactly like a hand-writtenBaseModel.Why
Issues #323, #761, and #772 all asked the same thing: how to drive a
tool's
inputSchemafrom a JSON Schema you already hold (from OpenAPI, aconfig file, a DB row) rather than a class written out in source. The
maintainer answer is "use a pydantic model as the parameter" — but the
example suite never showed how to get that model when it isn't declared
statically. This closes that documentation gap with a runnable variant.
Notes
create_model()result is opaque to static type checkers (its fieldsdon't exist until runtime, and a runtime variable can't appear in a type
annotation). A
TYPE_CHECKINGbranch aliases it to a same-shape declaredmodel so type checkers can see the fields; at runtime the dynamic class is
what
@mcp.tool()reflects over. This is called out in the README.greet_pydanticvariant — thepoint is purely how the model is obtained, not a different wire shape.
server_lowlevel.py,client.py, andREADME.mdare updated to coverthe new variant.
Validation
uv run --frozen ruff format --check/ruff check— cleanuv run --frozen pyright— 0 errorsuv run --frozen pytest tests/examples -k schema— 14 passed(in-memory/http × modern/legacy × server/server_lowlevel, plus the
manifest and story-shape checks)